#include "TriReader.h"
using namespace TriReader;

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <map>
using namespace std;
using namespace Math;

bool TriReader::OpenFile(const char* filename, ifstream& fin)
{
   // Try to open the file
   if(filename==NULL)
   {
      cerr << "Error: Invalid filename given to read file" << endl;
      return false;
   }

   /*#ifdef WIN32
     fin.open(filename, ios::in | ios::binary);
   #else*/
   fin.open(filename, ios::in);
   /*#endif*/

   if(!fin.rdbuf()->is_open())
   {
      cerr << "Error: file could not be opened for reading \""
         << filename << "\"" << endl;
      return false;
   }

   return true;
}

bool TriReader::ReadTriFile(const char* filename, Real*& vs, int*& fs, int& vn, int& fn)
{
   //Try to open the file
   ifstream fin;
   if(!TriReader::OpenFile(filename, fin))
   {
      return false;
   }

   int i;
   char buffer[256];

   fin >> buffer;

   if(strcmp(buffer, "TRI"))
   {
      cerr << "Error: Do not recognize file type. File data should have TRI header" << endl;
      return false;
   }

   fin >> vn >> fn;
   vs=new Real[vn*3];
   fs=new int[fn*3];

   // Read in the vertex coordinates
   for(i=0; i<vn*3; i+=3)
   {
       fin >> vs[i] >> vs[i+1] >> vs[i+2];
   }

   // Read in the face indices
   for(i=0; i<fn*3; i+=3)
   {
      fin >> fs[i] >> fs[i+1] >> fs[i+2];
   }

   return true;
}


bool TriReader::ReadParFile(const char* filename, Real*& vs, int*& fs, int& vn, int& fn)
{
   //Try to open the file
   ifstream fin;
   if(!TriReader::OpenFile(filename, fin))
   {
      return false;
   }

   int i;
   char buffer[256];

   fin >> buffer;

   if(strcmp(buffer, "PAR"))
   {
      cerr << "Error: Do not recognize file type. File data should have TRI header" << endl;
      return false;
   }

   fin >> vn >> fn;
   vs=new Real[vn*3];
   fs=new int[fn*3];

   // Read in the vertex coordinates
   for(i=0; i<vn*3; i+=3)
   {
      int dum;
       fin >> vs[i] >> vs[i+1] >> vs[i+2] >> dum;
   }

   // Read in the face indices
   for(i=0; i<fn*3; i+=3)
   {
      int dum;
      fin >> fs[i] >> fs[i+1] >> fs[i+2] >> dum;
   }

   return true;
}


bool TriReader::ReadOffFile(const char* filename, Real*& vs, int*& fs, int& vn, int& fn)
{
   //Try to open the file
   ifstream fin;

   if(!TriReader::OpenFile(filename, fin))
   {
      return false;
   }

   int i;
   char buffer[256];

   fin >> buffer;

   if(strcmp(buffer, "OFF"))
   {
      cerr << "Error: Do not recognize file type. File data should have OFF header" << endl;
      return false;
   }

   int numQuad;
   fin >> vn >> fn >> numQuad;
   vs=new Real[vn*3];
   fs=new int[fn*3];

   // Read in the vertex coordinates
   for(i=0; i<vn*3; i+=3)
   {
       fin >> vs[i] >> vs[i+1] >> vs[i+2];
   }

   int triangle;
   // Read in the face indices
   for(i=0; i<fn*3; i+=3)
   {
      fin >> triangle >> fs[i] >> fs[i+1] >> fs[i+2];
   }

   return true;
}

// vs => Vertices to be read            // vn => Number of vertices
// fs => Indices for the faces          // fn => Number of faces
// ts => UV Texture mapping to be read  // tn => Number of texture vertices     // tis => Indices for the face (texture vertices)

//bool TriReader::ReadObjFile(const char* filename, Real*& vs, int*& fs, int& vn, int& fn)

/**
    ReadObjFile: Given a filename of an .obj mesh. 
    It returns the arrays of vertices, faces, texture coordinates and texture indexes.

    @param filename [IN]: Filename of the texture.
    @param vs [OUT]: Buffer which contains all the vertices of the mesh, each vertex is built on three Reals.
    @param fs [OUT]: Buffer which contains all the faces of the mesh, each face is built on three indexes (int).
    @param ts [OUT]: Buffer which contains all the texture coordinates (u,v) of the mesh.
    @param tis [OUT]: Buffer which contains all the texture indexes to the ts buffer, three per face.
    @param vn [OUT]: Number of vertices that has the "vs" buffer.
    @param fn [OUT]: Number of faces that has the "fs" buffer.
    @param tn [OUT]: Number of texture coordinates has the buffer "ts".
*/
bool TriReader::ReadObjFile(const char* filename,
                            Real*& vs,
                            int*& fs,
                            Real*& ts,
                            int*& tis,
                            int& vn,
                            int& fn,
                            int& tn) {

    cout << "\nTriReader::ReadObjFile --> Loading ["<< filename <<"]\n";
    vector<double> pos;
    vector<double> normal;
    vector<double> tex;
    vector<int> nvert;
    vector<int> posind;
    vector<int> normalind;
    vector<int> texind;

    bool texdata = false;
    bool normaldata = false;

    ifstream ifile;
    ifile.open(filename);
    if (!ifile.is_open()) {
        cerr << "ERROR: TriReader::ReadObjFile --> could not open file [" << filename << "]\n";
        return false;
    }

    double x, y, z;
    while(!ifile.eof()) {
        string word;
        ifile >> word;
        if (word == "v") 
        {
            ifile >> x >> y >> z;
            pos.push_back(x);
            pos.push_back(y);
            pos.push_back(z);

        }
        else if (word == "vn") 
        {
            normaldata = true;
            ifile >> x >> y >> z;
            normal.push_back(x);
            normal.push_back(y);
            normal.push_back(z);

        } 
        else if (word == "vt")
        {
            texdata = true;
            ifile >> x >> y;
            tex.push_back(x);
            tex.push_back(1.0f - y); // Invierte la posicion para poner las texturas al derecho
        }
        else if (word == "f")
        {
            getline(ifile, word);
            istringstream line(word);
            int val;
            char aux;
            int nverts = 0;
            while (line >> val) 
            {
                nverts++;
                posind.push_back(val-1);
                line >> aux;
                if (texdata) 
                {
                    line >> val;
                    texind.push_back(val-1);
                }
                line >> aux;
                if (normaldata) 
                {
                    line >> val;
                    normalind.push_back(val-1);
                }
            }
            nvert.push_back(nverts);
        } 
        else 
        {
            getline(ifile, word);
        }
    }
    ifile.close();

    //The texture coordinates (u,v) are in "tex" array.
    //The texture indices, one per face vertex (u0, u1, u2) are in "texind" array.
    

    // triangulate convex polygons
    vector<int> nvertnew;
    vector<int> indnew;

    // We must also swap the index texture vertices
    vector<int> indNewTexture;
    vector<int> nvertnewTexture;

    for (int i=0, j=0; i<(int)nvert.size(); j+=nvert[i], i++) 
    {
        for (int k=2; k<nvert[i]; k++) 
        {
            #if 0 // Por mantener coherencia de fichero OFF-OBJ. Invertir aristas da problemas en ddcloth
            indnew.push_back(posind[j+k-1]);
            indnew.push_back(posind[j+k]);
            indnew.push_back(posind[j]);
            #else
            indnew.push_back(posind[j]);
            indnew.push_back(posind[j+k-1]);
            indnew.push_back(posind[j+k]);
            #endif
            nvertnew.push_back(3);

            if (texdata){
                // Now, the texture vertex.
                #if 0
                indNewTexture.push_back(texind[j+k-1]);
                indNewTexture.push_back(texind[j+k]);
                indNewTexture.push_back(texind[j]);
                #else
                indNewTexture.push_back(texind[j]);
                indNewTexture.push_back(texind[j+k-1]);
                indNewTexture.push_back(texind[j+k]);
                #endif

                nvertnewTexture.push_back(3);
            }
        }
    }

    posind.clear(); posind.reserve(indnew.size()); posind.resize(indnew.size());
    copy(indnew.begin(), indnew.end(), posind.begin());

    texind.clear(); texind.reserve(indNewTexture.size()); texind.resize(indNewTexture.size());
    copy(indNewTexture.begin(), indNewTexture.end(), texind.begin());




    //Correcting the texture coordinates, this method unwraps the mesh in order
    //to get each vertex with only ONE (u,v) texture coordinate.
    //Its duplicates vertices if it's necessary
    cout << "Correcting uv coordinates\n";
    correct_uv_coordinates(pos, normal, tex, posind, normalind, texind);
    

    // now, create the vertices and faces
    vn = (int)pos.size()/3;
    fn = (int)posind.size()/3;
    tn = (int)tex.size()/2;

    vs=new Real[vn*3];
    fs=new int[fn*3];
    ts=new Real[tn*2];
    tis=new int[fn*3];


    for (int i=0; i<(int)pos.size(); i++)
        vs[i] = pos[i];
    for (int i=0; i<(int)posind.size(); i++)
        fs[i] = posind[i];
    for (int i=0; i<(int)tex.size(); i++){
        if (tex[i] > 1)
            tex[i] = 1.0f;

        if (tex[i] < 0)
            tex[i] = 0.0f;

        ts[i] = tex[i];
    }
    for (int i=0; i<(int)texind.size(); i++)
        tis[i] = texind[i];

    //Correcting the indices of the faces, is some index is -1, we will add 1 to each index.
    
//NOTA: Esto debería estar antes de crear los arrays finales.
    /*
    bool has_to_be_corrected = false;
    for (int i=0; i<fn*3 && has_to_be_corrected == false; i++) {
        if (fs[i] < 0) {
            has_to_be_corrected = true;
        }
    }
    if (has_to_be_corrected == true) {
        for (int i=0; i<fn*3; i++) {
            fs[i] = fs[i] + 1;
            if (texind.size() > 0){
                tis[i] += 1;
            }
        }
    }
    */
    return true;
}




/**
    ReadObjFileNoUvCorrect: Given a filename of an .obj mesh. 
    It returns the arrays of vertices, faces, texture coordinates and texture indexes.

    @param filename [IN]: Filename of the texture.
    @param vs [OUT]: Buffer which contains all the vertices of the mesh, each vertex is built on three Reals.
    @param fs [OUT]: Buffer which contains all the faces of the mesh, each face is built on three indexes (int).
    @param ts [OUT]: Buffer which contains all the texture coordinates (u,v) of the mesh.
    @param tis [OUT]: Buffer which contains all the texture indexes to the ts buffer, three per face.
    @param vn [OUT]: Number of vertices that has the "vs" buffer.
    @param fn [OUT]: Number of faces that has the "fs" buffer.
    @param tn [OUT]: Number of texture coordinates has the buffer "ts".
*/
bool TriReader::ReadObjFileNoUvCorrect(const char* filename,
                            Real*& vs,
                            int*& fs,
                            Real*& ts,
                            int*& tis,
                            int& vn,
                            int& fn,
                            int& tn) {

    cout << "\nTriReader::ReadObjFileNoUvCorrect --> Loading ["<< filename <<"]\n";
    vector<double> pos;
    vector<double> normal;
    vector<double> tex;
    vector<int> nvert;
    vector<int> posind;
    vector<int> normalind;
    vector<int> texind;

    bool texdata = false;
    bool normaldata = false;

    ifstream ifile;
    ifile.open(filename);
    if (!ifile.is_open()) {
        cerr << "ERROR: TriReader::ReadObjFileNoUvCorrect --> could not open file [" << filename << "]\n";
        return false;
    }

    double x, y, z;
    while(!ifile.eof()) {
        string word;
        ifile >> word;
        if (word == "v") 
        {
            ifile >> x >> y >> z;
            pos.push_back(x);
            pos.push_back(y);
            pos.push_back(z);

        }
        else if (word == "vn") 
        {
            normaldata = true;
            ifile >> x >> y >> z;
            normal.push_back(x);
            normal.push_back(y);
            normal.push_back(z);

        } 
        else if (word == "vt")
        {
            texdata = true;
            ifile >> x >> y;
            tex.push_back(x);
            tex.push_back(1.0f - y); // Invierte la posicion para poner las texturas al derecho
        }
        else if (word == "f")
        {
            getline(ifile, word);
            istringstream line(word);
            int val;
            char aux;
            int nverts = 0;
            while (line >> val) 
            {
                nverts++;
                posind.push_back(val-1);
                line >> aux;
                if (texdata) 
                {
                    line >> val;
                    texind.push_back(val-1);
                }
                line >> aux;
                if (normaldata) 
                {
                    line >> val;
                    normalind.push_back(val-1);
                }
            }
            nvert.push_back(nverts);
        } 
        else 
        {
            getline(ifile, word);
        }
    }
    ifile.close();

    //The texture coordinates (u,v) are in "tex" array.
    //The texture indices, one per face vertex (u0, u1, u2) are in "texind" array.
    

    // triangulate convex polygons
    vector<int> nvertnew;
    vector<int> indnew;

    // We must also swap the index texture vertices
    vector<int> indNewTexture;
    vector<int> nvertnewTexture;

    for (int i=0, j=0; i<(int)nvert.size(); j+=nvert[i], i++) 
    {
        for (int k=2; k<nvert[i]; k++) 
        {
            #if 0 // Por mantener coherencia de fichero OFF-OBJ. Invertir aristas da problemas en ddcloth
            indnew.push_back(posind[j+k-1]);
            indnew.push_back(posind[j+k]);
            indnew.push_back(posind[j]);
            #else
            indnew.push_back(posind[j]);
            indnew.push_back(posind[j+k-1]);
            indnew.push_back(posind[j+k]);
            #endif
            nvertnew.push_back(3);

            if (texdata){
                // Now, the texture vertex.
                #if 0
                indNewTexture.push_back(texind[j+k-1]);
                indNewTexture.push_back(texind[j+k]);
                indNewTexture.push_back(texind[j]);
                #else
                indNewTexture.push_back(texind[j]);
                indNewTexture.push_back(texind[j+k-1]);
                indNewTexture.push_back(texind[j+k]);
                #endif

                nvertnewTexture.push_back(3);
            }
        }
    }

    posind.clear(); posind.reserve(indnew.size()); posind.resize(indnew.size());
    copy(indnew.begin(), indnew.end(), posind.begin());

    texind.clear(); texind.reserve(indNewTexture.size()); texind.resize(indNewTexture.size());
    copy(indNewTexture.begin(), indNewTexture.end(), texind.begin());


    // now, create the vertices and faces
    vn = (int)pos.size()/3;
    fn = (int)posind.size()/3;
    tn = (int)tex.size()/2;

    vs=new Real[vn*3];
    fs=new int[fn*3];
    ts=new Real[tn*2];
    tis=new int[fn*3];


    for (int i=0; i<(int)pos.size(); i++)
        vs[i] = pos[i];
    for (int i=0; i<(int)posind.size(); i++)
        fs[i] = posind[i];
    for (int i=0; i<(int)tex.size(); i++){
        if (tex[i] > 1)
            tex[i] = 1.0f;

        if (tex[i] < 0)
            tex[i] = 0.0f;

        ts[i] = tex[i];
    }
    for (int i=0; i<(int)texind.size(); i++)
        tis[i] = texind[i];

    return true;
}



bool TriReader::ReadSmfFile(const char* filename, Real*& vs, int*& fs, int& vn, int& fn)
{
    vector<double> pos;
   vector<double> normal;
   vector<double> tex;
   vector<int> posind;
   vector<int> normalind;
   vector<int> texind;

   bool normaldata = false;

   ifstream ifile;
   ifile.open(filename);
    if (!ifile.is_open()) {
        cerr << "could not open file" << endl;
        return false;
    }


   bool done = false;
   while(!done)
   {
      if (ifile.eof())
      {
         done = true;
         break;
      }

      string word;
      ifile >> word;
      if (word == "v")
      {
         double x, y, z;
         ifile >> x >> y >> z;
         pos.push_back(x);
         pos.push_back(y);
         pos.push_back(z);
      }
      else if (word == "n")
      {
         normaldata = true;
         double x, y, z;
         ifile >> x >> y >> z;
         normal.push_back(x);
         normal.push_back(y);
         normal.push_back(z);
      }
      else if (word == "f")
      {
         int x, y, z;
         ifile >> x >> y >> z;
         posind.push_back(x-1);
         posind.push_back(y-1);
         posind.push_back(z-1);
      }
      else
      {
         getline(ifile, word);
      }
   }
    ifile.close();


    // now, create the vertices and faces
   vn = (int)pos.size()/3;
    fn = (int)posind.size()/3;
    vs=new Real[vn*3];
   fs=new int[fn*3];


    for (int i=0; i<(int)pos.size(); i++)
        vs[i] = pos[i];
    for (int i=0; i<(int)posind.size(); i++)
        fs[i] = posind[i];

   //Correcting the indices of the faces, is some index is -1, we will add 1 to each index.
   bool has_to_be_corrected = false;
   for (int i=0; i<fn*3 && has_to_be_corrected == false; i++) {
      if (fs[i] < 0) {
         has_to_be_corrected = true;
      }
   }
   if (has_to_be_corrected == true) {
      for (int i=0; i<fn*3; i++) {
         fs[i] = fs[i] + 1;
      }
   }

    return true;
}



bool TriReader::ReadObjFileSingleMesh(ifstream& ifile, int vert_offset, Real*& vs, int*& fs, int& vn, int& fn)
{
    vector<double> pos;
   vector<double> normal;
   vector<double> tex;
   vector<int> nvert;
   vector<int> posind;
   vector<int> normalind;
   vector<int> texind;

   bool texdata = false;
   bool normaldata = false;

    if (!ifile.is_open()) {
        cerr << "file is not open" << endl;
        return false;
    }


   bool done = false;
   while(!done)
   {
      if (ifile.eof())
      {
         done = true;
         break;
      }

      string word;
      ifile >> word;
      if (word == "v")
      {
         double x, y, z;
         ifile >> x >> y >> z;
         pos.push_back(x);
         pos.push_back(y);
         pos.push_back(z);
      }
      else if (word == "vn")
      {
         normaldata = true;
         double x, y, z;
         ifile >> x >> y >> z;
         normal.push_back(x);
         normal.push_back(y);
         normal.push_back(z);
      }
      else if (word == "vt")
      {
         texdata = true;
         double x, y;
         ifile >> x >> y;
         tex.push_back(x);
         tex.push_back(y);
      }
      else if (word == "f")
      {
         getline(ifile, word);
         istringstream line(word);
         int val;
         char aux;
         int nverts = 0;
         while (line >> val)
         {
            nverts++;
            posind.push_back(val-1-vert_offset);
            line >> aux;
            if (texdata)
            {
               line >> val;
               texind.push_back(val-1-vert_offset);
            }
            line >> aux;
            if (normaldata)
            {
               line >> val;
               normalind.push_back(val-1-vert_offset);
            }
         }
         nvert.push_back(nverts);
      }
      else if (word == "surface")
      {
         done = true;
         getline(ifile, word);
      }
      else
      {
         getline(ifile, word);
      }
   }


    // triangulate convex polygons
   vector<int> nvertnew;
   vector<int> indnew;

   for (int i=0, j=0; i<(int)nvert.size(); j+=nvert[i], i++)
   {
      for (int k=2; k<nvert[i]; k++)
      {
         indnew.push_back(posind[j+k-1]);
         indnew.push_back(posind[j+k]);
         indnew.push_back(posind[j]);
         nvertnew.push_back(3);
      }
   }

   posind.clear(); posind.reserve(indnew.size()); posind.resize(indnew.size());
    copy(indnew.begin(), indnew.end(), posind.begin());



    // now, create the vertices and faces
   vn = (int)pos.size()/3;
    fn = (int)posind.size()/3;
    vs=new Real[vn*3];
   fs=new int[fn*3];


    for (int i=0; i<(int)pos.size(); i++)
        vs[i] = pos[i];
    for (int i=0; i<(int)posind.size(); i++)
        fs[i] = posind[i];


    return true;

}

void TriReader::ParseObjHeader(ifstream& ifile)
{
   bool done = false;
   while(!done)
   {
      string word;
      ifile >> word;
      if (word == "surface")
      {
         done = true;
      }
      getline(ifile, word);
   }
}



bool TriReader::ReadDCMeshFile(const char* filename, Real*& vs, int*& fs, int& vn, int& fn)
{
    vector<double> pos;
   vector<double> normal;
   vector<double> tex;
   vector<int> nvert;
   vector<int> posind;
   vector<int> normalind;
   vector<int> texind;

   ifstream ifile;
   ifile.open(filename);
    if (!ifile.is_open()) {
        cerr << "could not open file" << endl;
        return false;
    }


   bool done = false;
   while(!done)
   {
      if (ifile.eof())
      {
         done = true;
         break;
      }

      string word;
      ifile >> word;
      if (word == "v")
      {
         double x, y, z;
         ifile >> x >> y >> z;
         pos.push_back(x);
         pos.push_back(y);
         pos.push_back(z);
      }
      else if (word == "t")
      {
         //texdata = true;
         double x, y;
         ifile >> x >> y;
         tex.push_back(x);
         tex.push_back(y);
      }
      else if (word == "f")
      {
         getline(ifile, word);
         istringstream line(word);
         int val;
         int nverts = 0;

            while (line >> val)
         {
            nverts++;
            posind.push_back(val);
         }
         nvert.push_back(nverts);
      }
      else
      {
         getline(ifile, word);
      }
   }
    ifile.close();


    // triangulate convex polygons
   vector<int> nvertnew;
   vector<int> indnew;

   for (int i=0, j=0; i<(int)nvert.size(); j+=nvert[i], i++)
   {
      for (int k=2; k<nvert[i]; k++)
      {
         indnew.push_back(posind[j+k-1]);
         indnew.push_back(posind[j+k]);
         indnew.push_back(posind[j]);
         nvertnew.push_back(3);
      }
   }

   posind.clear(); posind.reserve(indnew.size()); posind.resize(indnew.size());
    copy(indnew.begin(), indnew.end(), posind.begin());


    // now, create the vertices and faces
   vn = (int)pos.size()/3;
    fn = (int)posind.size()/3;
    vs=new Real[vn*3];
   fs=new int[fn*3];


    for (int i=0; i<(int)pos.size(); i++)
        vs[i] = pos[i];
    for (int i=0; i<(int)posind.size(); i++)
        fs[i] = posind[i];

    return true;
}



bool TriReader::ReadTriFile(const char* filename, Real*& vs, int vn)
{
   //this reader only looks for the vertex data

    //Try to open the file
   ifstream fin;
   if(!TriReader::OpenFile(filename, fin))
   {
      return false;
   }

   int i;
   char buffer[256];

   fin >> buffer;

   if(strcmp(buffer, "TRI"))
   {
      cerr << "Error: Do not recognize file type. File data should have TRI header" << endl;
      return false;
   }

    int vn1, fn;
    fin >> vn1 >> fn;

    if (vn1 != vn) {
        cerr << "file does not have the same number of vertices!" << endl;
        return false;
    }

   // Read in the vertex coordinates
   for(i=0; i<vn*3; i+=3)
   {
       fin >> vs[i] >> vs[i+1] >> vs[i+2];
   }

   return true;
}


bool TriReader::ReadOffFile(const char* filename, Real*& vs, int vn)
{
   //this reader only looks for the vertex data

   //Try to open the file
   ifstream fin;
   if(!TriReader::OpenFile(filename, fin))
   {
      return false;
   }

   int i;
   char buffer[256];

   fin >> buffer;

   if(strcmp(buffer, "OFF"))
   {
      cerr << "Error: Do not recognize file type. File data should have OFF header" << endl;
      return false;
   }

   int numQuad,fn,vn1;
   fin >> vn1 >> fn >> numQuad;

    if (vn1 != vn) {
        cerr << "file does not have the same number of vertices!" << endl;
        return false;
    }

   // Read in the vertex coordinates
   for(i=0; i<vn*3; i+=3)
   {
       fin >> vs[i] >> vs[i+1] >> vs[i+2];
   }

   return true;
}


bool TriReader::ReadObjFile(const char* filename, Real*& vs, int vn) {
    //this reader only looks for the vertex position data.
    // this reader uses different file IO functions that seem to be faster. It makes a big difference
    // in debug mode. Since this method is used for the scripted objects and called many times, I use this
    // faster approach

    // open the file
    FILE *file;
    file = fopen(filename, "r");

    if(!file) {
        cerr << "could not find file";
        return false;
    }

    int vn1;
    // get nof vertices and faces
    vn1 = 0;

    while(!feof(file))
    {
        // get the next line
        char strLine[200];
        char * result = fgets(strLine, 200, file);

        // handle vertex data
        if(strncmp(strLine, "v ", 2) == 0)
        {
            vn1++;
        }
    }

    if (vn1 != vn) {
        cerr << "file does not have the same number of vertices!" << endl;
        return false;
    }

    rewind(file);
    vn1 = 0;

    while(!feof(file))
    {
        // get the next line
        char strLine[200];
        char * result = fgets(strLine, 200, file);

        // handle vertex data
        if(strncmp(strLine, "v ", 2) == 0)
        {
            float f1,f2,f3;
            sscanf(strLine, "v %f %f %f", &f1, &f2, &f3);

            vs[vn1*3] = f1;
            vs[vn1*3+1] = f2;
            vs[vn1*3+2] = f3;

            vn1++;
        }
    }

    fclose(file);

    return true;
}


bool TriReader::ReadPairsFile(const char* filename, int*& ids, int& n)
{
   //Try to open the file
   ifstream fin;
   if(!TriReader::OpenFile(filename, fin))
   {
      return false;
   }

   int i;

   fin >> n;
   ids=new int[n*2];

   // Read in the indices
   for(i=0; i<n*2; i+=2)
   {
       fin >> ids[i] >> ids[i+1];
   }

   return true;
}


using namespace std;


void TriReader::correct_uv_coordinates(vector<double> &pos, 
                                       vector<double> &normal,
                                       vector<double> &tex,
                                       vector<int>    &posind,
                                       vector<int>    &normalind,
                                       vector<int>    &texind) {

    //~ cout << "TriReader::correct_uv_coordinates: \n";
    //~ cout << "  Vertices: " << pos.size()/3 << endl;
    //~ cout << "  Normals: " << normal.size()/3 << endl;
    //~ cout << "  Textures: " << tex.size()/2 << endl;

    //~ cout << "  Vertex ind: " << posind.size() << endl;
    //~ cout << "  Normal ind: " << normalind.size() << endl;
    //~ cout << "  Texture ind: " << texind.size() << endl;

    if (posind.size() != texind.size()) {
        //cout << "TriReader::correct_uv_coordinates --> Unwarping unnecessary.\n";
        return;
    }

    //~ unsigned int max_ind = 0;
    //~ unsigned int min_ind = 10000;
    //~ for (unsigned int i=0; i<posind.size(); i++) {
        //~ if (posind[i] > max_ind) {
            //~ max_ind = posind[i];
        //~ }
        //~ if (posind[i] < min_ind) {
            //~ min_ind = posind[i];
        //~ }
    //~ }
    //~ cout << "Max index " << max_ind << "  min index " << min_ind << endl;

    string key;
    int key_val;
    
    //Starting with an empty vertices vector.
    vector<double> new_pos;
    vector<int> new_posind;
    
    //Creating an empty map, for storage of coincidences.
    map<string, int> coincidences;

    //~ unsigned int found = 0;
    //~ unsigned int not_found = 0;
    new_posind.resize(posind.size());
    
    char s_value[500];
    //Reading all the faces.   
    for (unsigned int i=0; i<posind.size(); i++) {
        //Creating the key for each vertex.
        sprintf( s_value, "%d", posind[i]);
        key  = s_value;
        key += "_";
        sprintf( s_value, "%d", texind[i]);
        key += s_value;

        //Searching the key of this vertex
        if (coincidences.find(key) == coincidences.end()) {
            //Key not found, creating new vertex and key.
            key_val = (int) new_pos.size() / 3;
            coincidences[key] = key_val;
            
            new_pos.push_back( pos[posind[i]*3]   );
            new_pos.push_back( pos[posind[i]*3+1] );
            new_pos.push_back( pos[posind[i]*3+2] );
            //~ not_found++;
        } else {
            //Key found, using found vertex.
            key_val = coincidences[key];
            //~ found++;
        }
        //Reasigning the position of the vertex of this face.
        new_posind[i] = key_val;
    }
    //Only a obj file is transformated if it is necessary to duplicate vertices.
    if (pos.size() != new_pos.size()) {
        cout << "  Initial Vertices: " << pos.size()/3 << endl;
        cout << "  Unwrapped Vertices: " << new_pos.size()/3 << endl;
        //~ cout << "  Found Keys: " << found << "  not found keys: " << not_found << endl;
        pos.clear();
        pos.assign(new_pos.begin(), new_pos.end());

        posind.clear();
        posind.assign(new_posind.begin(), new_posind.end());        
    }
    new_pos.clear();
    new_posind.clear();
    coincidences.clear();
}




